<template>
    <el-dialog
        ref="departDialogRef"
        v-model="visible"
        class="zw-depart-dialog"
        width="800px"
        draggable
        append-to-body
        @close="handleClose"
        @open="handleOpen">
        <template #header>
            <div>
                选择员工
                <span v-if="props.limitNum && props.limitNum > 0" class="dialog-header-tip">
                    （因企微限制，引流员工上限为{{ props.limitNum }}人）
                </span>
            </div>
        </template>
        <div class="depart_box">
            <div class="depart_l">
                <el-input
                    v-model="searchName"
                    class="search_name"
                    placeholder="搜索成员、部门"
                    :prefix-icon="Search"
                    clearable
                    @input="handleSearch" />
                <el-tree-v2
                    ref="treeRef"
                    class="zw-tree-box"
                    :props="defaultProps"
                    :filter-method="handleFilterMethod"
                    :check-strictly="props.selectType === 'all'"
                    show-checkbox
                    :height="400"
                    @check-change="checkCurrentChange">
                    <template #default="{ node, data }">
                        <span class="prefix">
                            <el-icon v-if="data.type == 'user'" class="depart_member_icon">
                                <UserFilled />
                            </el-icon>
                            <img
                                v-else
                                class="depart_icon mr2"
                                src="//img.static-keyid.cn/toolspace/scrm/2023/09/1693908003949sex7051m3c9vhbdl.png" />
                        </span>
                        <el-tooltip v-if="data.disabled" :content="data.select_msg" placement="top">
                            <span>{{ node.label }}</span>
                        </el-tooltip>
                        <span v-if="!data.disabled" @click="setCurrentKey(data)">{{ node.label }}</span>
                        <span v-if="data.type !== 'user'">（{{ data.user_count }}）</span>
                    </template>
                </el-tree-v2>
            </div>
            <div class="depart_r">
                <div class="depart_select_title">
                    <span>已选择的员工（{{ selectedDepartList.length }}）</span>
                    <el-button class="empty" link @click="clearSelectItem">清空</el-button>
                </div>
                <el-scrollbar :height="380">
                    <div v-for="item in selectedDepartList" :key="item.id" class="seled_member">
                        <div class="item_member">
                            <el-icon v-if="item.type == 'user'" class="seled_icon">
                                <UserFilled />
                            </el-icon>
                            <img
                                v-else
                                class="depart_icon"
                                src="//img.static-keyid.cn/toolspace/scrm/2023/09/1693908003949sex7051m3c9vhbdl.png" />
                            <span class="member_name">
                                {{ item.name }}
                                <span v-if="item.isLocal == 1">(本地)</span>
                            </span>
                        </div>
                        <el-icon class="remove_icon" @click="removeItem(item)">
                            <Close />
                        </el-icon>
                    </div>
                </el-scrollbar>
            </div>
        </div>
        <template #footer>
            <el-button @click="cancel"> 取消 </el-button>
            <el-button type="primary" @click="submit"> 保存 </el-button>
        </template>
    </el-dialog>
</template>
<script lang="ts" setup>
import { ref, computed, nextTick, getCurrentInstance } from 'vue';
import { cloneDeep, debounce } from 'lodash';
import { Search, UserFilled, Close } from '@element-plus/icons-vue';
import { ElTreeV2, ElDialog, ElButton, ElInput, ElTooltip, ElIcon, ElLoading, ElScrollbar } from 'element-plus';
import { getDepartUserList } from '../api/selectDepart';

import { SEARCH_ENUM, ISearchType, ISelectType, IPropsDepartItem } from './type';
import { TreeKey } from 'element-plus/es/components/tree-v2/src/types';
import { LoadingInstance } from 'element-plus/es/components/loading/src/loading';

const app = getCurrentInstance();

const emit = defineEmits<{
    /**
     * 点击确定的回调事件，会携带已选择的员工/部门参数 (Array<{ id, name, .... }>) => void
     */
    (e: 'submit', departData: Array<IPropsDepartItem>): void;
    /**
     * v-model的绑定事件.
     */
    (e: 'update:modelValue', modelValue: boolean): void;
    /**
     * v-model:selected的绑定事件.
     */
    (e: 'update:selected', selected: Array<IPropsDepartItem>): void;
}>();

defineOptions({
    name: 'ZwUnityKitSelectDepart',
    inheritAttrs: false
});

interface IProps {
    /**
     * 选择员工弹窗的显示与隐藏
     */
    modelValue: boolean;
    /**
     * 是否多选
     */
    multiple?: boolean;
    /**
     * 选择员工的类型
     * @description user 选择员工，选择部门时会选择以下员工
     * @description all 选择全部, 部门和员工可以单独选择
     */
    selectType?: ISelectType;
    /**
     * 是否查询本地员工
     * all: 查询全部, yes: 查询本地员工, not: 查询非本地员工
     */
    isLocal?: ISearchType;
    /**
     * 是否查询具有企微外部联系人权限
     * all: 查询全部, yes: 查询具有外部人权限, not: 查询未具有外部人权限
     */
    isWxFollowUser?: ISearchType;
    /**
     * 查询开启回话存档的
     * all: 查询全部, yes: 查询开启回话存档员工, not: 查询未开启回话存档员工
     */
    isOpenSessionArchive?: ISearchType;
    /**
     * 是否查询授权scrm系统的员工, 授权信息： 手机号，头像，员工二维码
     * all: 查询全部, yes: 查询授权的, not: 查询未授权的
     */
    hasAuthorization?: ISearchType;
    /**
     * 最大限制选择的数量,如果设置了，则在顶部会显(示因企微限制，引流员工上限为{limitNum}人)
     */
    limitNum?: number;
    /**
     * 已选择员工数组集合，每一项必须包含id, Array<{ id, name, isDelete, [prop: string]: any }>
     */
    selected?: Array<IPropsDepartItem>;
    /**
     * 自定义禁用的方法, 用来判断该员工/部门是否可以选择
     * 接收当前员工/部门的对象最为参数，应该返回 [ disabled : boolean, disabledMessage: string ]
     */
    disabledDepart?: (depart: IPropsDepartItem) => [boolean, string];
}

const props = withDefaults(defineProps<IProps>(), {
    modelValue: false,
    multiple: true,
    isLocal: 'not',
    isWxFollowUser: 'yes',
    isOpenSessionArchive: 'all',
    hasAuthorization: 'yes',
    selectType: 'user',
    selected: () => [],
    limitNum: undefined,
    disabledDepart: undefined
});

/**
 * 是否显示选择员工弹窗
 */
const visible = computed({
    get() {
        return props.modelValue;
    },
    set(value) {
        emit('update:modelValue', value);
    }
});

/**
 * 打开选择员工弹窗
 * @description 初始化部门数据
 */
const handleOpen = () => {
    initDepartData();
};
/**
 * 关闭选择员工弹窗
 * @description 初始化组件数据
 */
const handleClose = () => {
    searchName.value = '';
    DEPART_DATA_MAP.clear();
    clearSelectItem();
};

/** 树形选择器ref */
const treeRef = ref<InstanceType<typeof ElTreeV2>>();
/** 弹窗的ref */
const departDialogRef = ref<InstanceType<typeof ElDialog>>();
/* ----------------------------选择员工提交-start---------------------------- */

/**
 * 点击取消按钮的事件
 * @description 关闭弹窗，清空搜索状态
 */
const cancel = () => {
    visible.value = false;
};

/**
 * 点击确定按钮的事件
 * @description 关闭弹窗，清空搜索状态，触发submit事件。
 */
const submit = () => {
    const submitData = cloneDeep(selectedDepartList.value);
    emit('submit', submitData);
    emit('update:selected', submitData);
    visible.value = false;
};

/**
 * 已经选择的数据
 */
const selectedDepartList = ref<Array<IPropsDepartItem>>([]);

/**
 * 选择部门和员工
 */
const checkCurrentChange = async data => {
    const filterMethod = props.selectType === 'user' ? item => item.type === 'user' : () => true;
    let checkedNodes: IPropsDepartItem[] = [];
    let checkedNodesList: string[] = [];

    await nextTick();
    if (props.multiple) {
        checkedNodes = treeRef.value?.getCheckedNodes()?.filter(filterMethod) as IPropsDepartItem[];
        checkedNodes = checkedNodes.slice(0, props.limitNum || checkedNodes.length);
        checkedNodesList = checkedNodes.map(item => item[DEPART_KEY] as string);
    } else {
        if (data.type === 'user') {
            checkedNodesList = [data[DEPART_KEY]];
            checkedNodes = [data];
        } else {
            // 如果点击的是部门，跳出执行函数，因为单选的情况下点击是无效的状态
            treeRef.value?.setCheckedKeys([selectedDepartList.value[0][DEPART_KEY] as TreeKey]);
            return;
        }
    }

    treeRef.value?.setCheckedKeys(checkedNodesList);
    selectedDepartList.value = cloneDeep(checkedNodes);
};

/**
 * 移除当前选择员工
 */
const removeItem = item => {
    const index = selectedDepartList.value.findIndex(v => v.id === item.id);
    if (index > -1) {
        selectedDepartList.value.splice(index, 1);
    }
    treeRef.value?.setChecked(item[DEPART_KEY], false);
};

/**
 * 清空所有选择员工
 */
const clearSelectItem = () => {
    selectedDepartList.value.length = 0;
    treeRef.value?.setCheckedKeys([]);
};

/**
 * 点击名称手动勾选选中状态，
 * 此方法是为了优化交互的体验
 * 考虑到勾选部门会有展开收起的情况可能会导致体验感很差。因此部门的不做优化
 */
const setCurrentKey = async data => {
    // 如果点击的是部门，跳出执行函数
    if (data.type !== 'user') {
        return;
    }
    treeRef.value?.setChecked(
        data[DEPART_KEY],
        !selectedDepartList.value.find(item => item[DEPART_KEY] === data[DEPART_KEY])
    );
    await nextTick();
    checkCurrentChange(data);
};
/* ----------------------------选择员工提交-end---------------------------- */

/* ----------------------------搜索员工-start---------------------------- */
const searchName = ref('');

const handleFilterMethod = (query: string, node: IPropsDepartItem) => {
    return node.name?.includes(query);
};

/**
 * 输入框搜索
 */
const handleSearch = debounce(() => {
    treeRef.value?.filter(searchName.value);
    if (!searchName.value) {
        treeRef.value?.setExpandedKeys([String(departData?.[DEPART_KEY]) as TreeKey]); // 设置默认展开
    }
});

/* ----------------------------搜索员工-end---------------------------- */

/* ----------------------------获取员工数据-start---------------------------- */

/**
 * 员工数据数组
 */
let departData = null;

/**
 * 区分每个员工/或者部门唯一字段
 */
const DEPART_KEY = 'd_u_unique_id';

const defaultProps = {
    children: 'children',
    label: 'name',
    disabled: 'disabled',
    value: DEPART_KEY
};

/**
 * 初始化员工数据
 */
const initDepartData = async () => {
    const loading: LoadingInstance = ElLoading.service({
        target: departDialogRef.value?.dialogContentRef.$el
    });
    try {
        const params = {
            is_wx_follow_user: SEARCH_ENUM[props.isWxFollowUser],
            is_open_session_archive: SEARCH_ENUM[props.isOpenSessionArchive],
            has_authorization: SEARCH_ENUM[props.hasAuthorization],
            is_local: SEARCH_ENUM[props.isLocal]
        };

        const res = await getDepartUserList(app, params);

        const treeData = mergeDepartChildren([res]);
        treeRef.value?.setData(treeData);
        treeRef.value?.filter(searchName.value);
        treeRef.value?.setExpandedKeys([res[DEPART_KEY]]); // 设置默认展开

        await nextTick();
        // 设置默认选中
        const selected: Array<IPropsDepartItem> = [];
        props.selected.forEach(item => {
            const selectItem: IPropsDepartItem = DEPART_DATA_MAP.get(item.id);
            if (selectItem) {
                selected.push(selectItem);
            }
        });
        treeRef.value?.setCheckedKeys(selected.map(item => String(item[DEPART_KEY]) as TreeKey));
        selectedDepartList.value = cloneDeep(selected);

        // 存储接口的值
        departData = res;
    } finally {
        loading?.close?.();
    }
};

const DEPART_DATA_MAP = new Map();
/**
 * 处理员工数据的子元素
 */
const mergeDepartChildren = (data: IPropsDepartItem[]) => {
    const arr: IPropsDepartItem[] = [];
    data.forEach((item: IPropsDepartItem) => {
        if (item.users?.length) {
            item.members = item.users.length;
            item.children = [...(item.children || []), ...item.users];
            item.users = null;
        }
        if (item.children?.length) {
            item.children = mergeDepartChildren(item.children);
        }

        // 自定义禁用的文案
        if (props.disabledDepart) {
            const disabledMessage = props.disabledDepart(item);
            const [disabled, select_msg] = Array.isArray(disabledMessage) ? disabledMessage : [];
            item.disabled = disabled;
            item.select_msg = select_msg;
        }

        DEPART_DATA_MAP.set(item.id, item);
        arr.push(item);
    });
    return arr;
};
/* ----------------------------获取员工数据-end---------------------------- */
</script>

<style lang="scss" scoped>
@import './Index';
</style>
